/****************************************************
*	OSMF Edge Media Player version 1.2.0
* 
*	Author: Emanuele Manco
* 	E-Mail: hello@flashedge.net
*	Web: http://activeden.net/user/flashedge
*  
*****************************************************/

package net.flashedge.display 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.GradientType;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filters.BlurFilter;
	import flash.filters.DisplacementMapFilter;
	import flash.filters.GlowFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundMixer;
	import flash.net.URLRequest;
	import flash.system.Security;
	import flash.utils.ByteArray;
	

	public class Spectrum extends Sprite
	{
		public var w:Number;
		public var h:Number;
		
		public var enabled:Boolean = false;
		public var filtersEnabled:Boolean = true;
		
		private var container:Sprite;

		private var sound:Sound;
		private var soundChannel:SoundChannel;
		private var byteArray:ByteArray;
		private var spectrumMode:Boolean;
 		
 		private var max:int;
		private var offset:Number;
		private var bar:Sprite;
		private var centerY:int;
		
		private var grad:Shape;
		private var gradBmd:BitmapData;
		
		private var rect:Rectangle;
		private var bmd:BitmapData;
		private var bmp:Bitmap;
		private var blur:BlurFilter;
		private var target:Sprite;
		
		private var radius:Number;
		private var rotatio:Number;
		private var vs:Number;
		
		private var displace:DisplacementMapFilter;;
		
		public function Spectrum() 
		{
			
		}
		
		public function init():void {
			container = new Sprite();

			spectrumMode = false;
	 		
	 		max = 256;
			offset = w/max;
			bar = new Sprite();
			centerY = h/2;
			
			grad = new Shape();
			gradBmd = new BitmapData(w, h);
			
			rect = new Rectangle(0, 0, w, h);
			bmd = new BitmapData(rect.width, rect.height, true, 0x00000000);
			bmp = new Bitmap(bmd);
			blur = new BlurFilter(3, 3, 1);
			target = bar;
			
			radius = 100;
			rotatio = 0;
			vs = 1.03;

			addChild(container);
			addChild(bar);
			
			var barFilter = new GlowFilter(0xFFFFFF, 0.5, 4, 4, 2, 1);
			bar.filters = [barFilter];
			
			grad.graphics.beginGradientFill(GradientType.LINEAR, [0xFF0000, 0x0000FF], [100, 100], [0, 255]);
			grad.graphics.drawRect(0, 0, w, h);
			grad.graphics.endFill();
		}
		
		private function enterFrameHandler(event:Event):void
		{
			spectrum();
			if (filtersEnabled ) { render(); }
		} 

		private function spectrum():void
		{
			if (enabled) { var n:Number = 0;
			
			byteArray = new ByteArray();
			SoundMixer.computeSpectrum(byteArray, spectrumMode, 0);
			
			bar.graphics.clear();
			bar.graphics.lineStyle(2, 0xFFFFFF);
			bar.graphics.moveTo(-1, centerY);
			
			for(var i:int=0; i < max; i++)
			{
				if (i % 2 == 0)
				{
					n = byteArray.readFloat()*(h*.3);
					var px:int = offset * i;
					bar.graphics.lineTo(px, centerY-n);
				}
			}
			
			bar.graphics.lineTo(w+10, centerY);
			} else {
			bar.graphics.clear();
			}
		}

		private function render():void
		{
			if (enabled) {
				
				var radian:Number = Math.PI/180 * rotatio;
				var val:Number = Math.sin(radian) * radius;
				rotatio += 1;
				
				var r:Number = -2;
				var g:Number = Math.abs(val / 20) * -1;	
				var b:Number = val * 1.5-200; 
				
				container.transform.colorTransform = new ColorTransform(1, 1, 1, 1, r, g, b, 100);
			
				var matrix:Matrix = new Matrix();
				matrix.scale(vs, vs);
				matrix.tx = (rect.width * vs - rect.width) / 2 * -1;
				matrix.ty = (rect.height * vs - rect.height) / 2 * -1;
				
				bmd.draw(this, matrix);
				bmd.applyFilter(bmd, rect, new Point(), blur);
				
				displace.componentX = rotatio;
				container.filters = [displace];
				
				container.numChildren > 0 ? container.removeChildAt(0) : trace ("nothing to clear");
				
				container.addChild(bmp);
				
			} else {
				
				for (var i = 0; i < container.numChildren; i++) {
					container.removeChildAt(0);
					}
				container.graphics.clear();
				
				removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			}
		}

		private function xRotateAt(matrix:Matrix, x:Number, y:Number, degree:Number):Matrix
		{
 			var point:Point = new Point(x, y);
			point = matrix.transformPoint(point);
			matrix.tx -= point.x;
			matrix.ty -= point.y;
			matrix.rotate(degree * (Math.PI/180));
			matrix.tx += point.x;
			matrix.ty += point.y;
		  
			return matrix;
		} 
		
		public function arrange(newWidth:Number, newHeight:Number):void 
		{	
			w = newWidth;
			h = newHeight;
			
			container.graphics.clear();
	 
			offset = w/max;
			centerY = h/2;
			
			gradBmd.dispose();
			gradBmd = null;
			gradBmd = new BitmapData(w, h);
			
			rect.setEmpty();
			rect = null;
			rect = new Rectangle(0, 0, w, h);
			
			bmd.dispose();
			bmd = null;
			bmd = new BitmapData(rect.width, rect.height, true, 0x00000000);
			
			bmp.bitmapData.dispose();
			bmp = null;
			bmp = new Bitmap(bmd);
			target = bar;
			
			displace = null;
			displace = new DisplacementMapFilter(gradBmd, null, 0, 0, 0, 0, "wrap", 0xFF0000, 1);

			grad.graphics.clear();
			grad.graphics.beginGradientFill(GradientType.LINEAR, [0xFF0000, 0x0000FF], [100, 100], [0, 255]);
			grad.graphics.drawRect(0, 0, w, h);
			grad.graphics.endFill();
			gradBmd.draw(grad);
		}
		
		public function activate():void {
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		
		public function clear():void {
			
			container.graphics.clear();
			
			gradBmd.dispose();
			gradBmd = null;
			
			rect.setEmpty();
			rect = null;
			
			bmd.dispose();
			bmd = null;
			
			bmp.bitmapData.dispose();
			bmp = null;
			
			displace = null;
			grad.graphics.clear();
			
			if (this.hasEventListener(Event.ENTER_FRAME)) {
				removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			}
		}
	}

}